//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <drvpub.h>

#include <bvd1bd.h>
#include "xllp_mmc.h"
#include "xllp_common.h"
#include <bulverde.h>
#include <Bvd1.h>
#include <BVD_UDC_Bits.h>

#include "SDBusDriver.h"
#include "SDClient.h"

CSDBusDriver g_SDBus;
CSDClient g_SDCard;

void dumpregs(P_XLLP_MMC_T pMmc)
{
    DEBUGCHK(_REGSD,\
        kprintf("\rMMC_STAT   %08x   MMC_CLKRT    %08x\n \
            \rMMC_CMD    %08x   MMC_SPI      %08x\n \
            \rMMC_CMDAT  %08x   MMC_RESTO    %08x\n \
            \rMMC_RDTO   %08x   MMC_BLKLEN   %08x\n \
            \rMMC_NUMBLK %08x   MMC_PRTBUF   %08x\n \
            \rMMC_I_MASK %08x   MMC_I_REG    %08x\n \
            \rMMC_ARGH   %08x   MMC_ARGL     %08x\n \
            \rMMC_RDWAIT %08x   MMC_BLKS_REM %08x\n",
            pMmc->MMC_STAT,  pMmc->MMC_CLKRT,
            pMmc->MMC_CMD - 0x40,   pMmc->MMC_SPI,
            pMmc->MMC_CMDAT, pMmc->MMC_RESTO,
            pMmc->MMC_RDTO,  pMmc->MMC_BLKLEN,
            pMmc->MMC_NUMBLK,pMmc->MMC_PRTBUF,
            pMmc->MMC_I_MASK,pMmc->MMC_I_REG,
            pMmc->MMC_ARGH,  pMmc->MMC_ARGL,
            pMmc->MMC_RDWAIT,pMmc->MMC_BLKS_REM)\
     );
}


ECode IsCardInsert(void *arg)
{
    CSDBusDriver* pBus = (CSDBusDriver*)arg;
    SystemTime TO;
    UInt32 mSec;
    Boolean TimeOut = FALSE;
    ECode ec = NOERROR;

    if ( GPLR0 & XLLP_BIT_12 ) {//SD Card Insert
        if ( SD_API_FAILED(pBus->HandleAddDevice()) ) {
            kputs("Please Unplug the MiniSD Card and Plug again!\n");
            DzGetSystemTime(&TO);
            mSec = TO.seconds;
            while(GPLR0 & XLLP_BIT_12) {
                DzGetSystemTime(&TO);
                if ( (TO.seconds - mSec) > 50) {
                    TimeOut = TRUE;
                    ec = E_DOES_NOT_EXIST;
                    break;
                }
            }
            mSec = TO.seconds;
            while (!TimeOut) {
                DzGetSystemTime(&TO);
                if (GPLR0 & XLLP_BIT_12) {
                    M_Delay(100);
                    if (GPLR0 & XLLP_BIT_12) {
                        if ( SD_API_SUCCESS(pBus->HandleAddDevice()) ) {
                            pBus->m_CardInsert = TRUE;
                        }
                        break;
                    }
                }
                else {
                    if ( (TO.seconds - mSec) > 50) {
                        TimeOut = TRUE;
                        ec = E_DOES_NOT_EXIST;
                        break;
                    }
                }
            }
        }
    }
    else {
        ec = E_DOES_NOT_EXIST;
    }

    return ec;
}

CSDBusDriver::CSDBusDriver()
{
}

CSDBusDriver::~CSDBusDriver()
{
}

ECode CSDBusDriver::Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */IEvent * * ppCompletionEvent)
{
    ECode ec = NOERROR;
    AcquireLock();
    if (!m_CardInsert) {
        ReleaseLock();
        return E_DOES_NOT_EXIST;
    }
    ec =  g_SDCard.Read(   u64Offset,
                            bytesToRead,
                            pBuffer,
                            ppCompletionEvent  );
	ReleaseLock();
	return ec;
}


ECode CSDBusDriver::Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec = NOERROR;
    AcquireLock();
    if (!m_CardInsert) {
        ReleaseLock();
        return E_DOES_NOT_EXIST;
    }

    ec = g_SDCard.Write(   u64Offset,
                            buffer,
                            pBytesWritten,
                            ppCompletionEvent  );

    ReleaseLock();
    return ec;
}


ECode CSDBusDriver::Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{
/*
    if (SDMMC_INIT == nControlCode) {
        if (SD_API_FAILED(HandleAddDevice())) {
            return IsCardInsert(this);
        }
        return NOERROR;
    }
*/
    ECode ec = NOERROR;
    UInt32 Cmd = (UInt32)nControlCode;

#if defined (_PWM_SET)
    long *Values;
#endif

    switch(Cmd) {
        case 1000://Bus Suspend
            BusPowerDown();
            break;

        case 1001://Bus Resume
            BusPowerUp();
            break;

        case 1002://Bus Power On
            Initialize();
            break;

        case SDMMC_INIT:
            ec = HandleAddDevice();
            if (SD_API_FAILED(ec)) {
                ec = IsCardInsert(this);
            }
            break;

#if defined (_PWM_SET)
        case 2006:
            Values = CONV(long*, pOutBuffer);
            Values[0]  = GPLR0;
            Values[1]  = GPLR1;
            Values[2]  = GPLR2;
            Values[3]  = GPLR3;

            Values[4]  = GPDR0;
            Values[5]  = GPDR1;
            Values[6]  = GPDR2;
            Values[7]  = GPDR3;

            Values[8]  = GRER0;
            Values[9]  = GRER1;
            Values[10] = GRER2;
            Values[11] = GRER3;

            Values[12] = GFER0;
            Values[13] = GFER1;
            Values[14] = GFER2;
            Values[15] = GFER3;

            Values[16] = GEDR0;
            Values[17] = GEDR1;
            Values[18] = GEDR2;
            Values[19] = GEDR3;
            SETBUF(long, 20, pOutBuffer);
            break;
#endif

        default:
            ec = g_SDCard.Control(nControlCode,
                            inBuffer,
                            pOutBuffer,
                            ppCompletionEvent);
            break;
    }

    return ec;
}

void CSDBusDriver::Dispose()
{

}

SD_API_STATUS CSDBusDriver::Initialize()
{
    m_CardInsert = FALSE;
    m_Initialized = TRUE;
    m_Powered = TRUE;
    RefCnt = 0;
    m_CliReg = FALSE;
    SD_API_STATUS ec = SD_API_STATUS_SUCCESS;
	m_pvGPIOReg = (P_XLLP_GPIO_T )(GPIO_BASE_U_VIRTUAL);
	m_pvMMCReg = (P_XLLP_MMC_T )(MMC_BASE_U_VIRTUAL);
    m_pvClockRegs = (XLLP_CLKMGR_T *)(CLK_BASE_U_VIRTUAL);
    XllpMmcSdHWInit(m_pvGPIOReg, m_pvClockRegs, NULL);
	M_Delay(1);   //wait 1ms per MMC specification.
    ec = HandleAddDevice();
//    IsCardInsert(this);
    return ec;
}

void CSDBusDriver::BusPowerUp()
{
    if (m_Initialized && !(m_Powered)) {
        XllpMmcSdHWInit(m_pvGPIOReg, m_pvClockRegs, NULL);
    	M_Delay(1);   //wait 1ms per MMC specification.
    	m_pvMMCReg->MMC_I_MASK = 0xFF;			// enable all interrupts
        startMMCClock();
        m_Powered = TRUE;
    }
}

void CSDBusDriver::BusPowerDown()
{
    if (m_Initialized && m_Powered) {
        stopMMCClock();
        XllpMmcSdHwShutdown(m_pvClockRegs, NULL);
        m_Powered = FALSE;
    }
}


void CSDBusDriver::SetupBusInterrupt(UInt8 intr)
{
    XllpMmcSdInts(m_pvMMCReg, intr);
}


SD_API_STATUS CSDBusDriver::HandleAddDevice()
{
    AcquireLock();
    SD_API_STATUS RetVal = SD_API_STATUS_UNSUCCESSFUL;
    if (m_Initialized) {
        if (!m_Powered) {
            BusPowerUp();
            m_Powered = TRUE;
        }
        RetVal = SDLoadDevice();
        if (SD_API_SUCCESS(RetVal)) {
            m_CardInsert = TRUE;
        }
    }
	ReleaseLock();
    return RetVal;
}

SD_API_STATUS CSDBusDriver::HandleRemoveDevice()
{
    AcquireLock();
    m_CardInsert = FALSE;
    BusPowerDown();
    m_Powered = FALSE;
	ReleaseLock();
    return SD_API_STATUS_SUCCESS;
}

SD_API_STATUS CSDBusDriver::SDLoadDevice()
{
    ECode ec;
    GRER0 &= ~(1 << 12);
    GFER0 &= ~(1 << 12);

    ec = g_SDCard.Initialize();
    GRER0 |= (1 << 12);
    GFER0 |= (1 << 12);

    return ec;

}

SD_API_STATUS CSDBusDriver::SDUnloadDevice()
{
    DEBUGCHK(_SUCSD, kprintf("SD/MMC SDUnloadDevice!\n"));
    return SD_API_STATUS_SUCCESS;
}


static DzEvent g_SdEvent;
static Boolean IsInPnPThd = FALSE;

void CDECL MiniSDPnPIsr(void *pvDevice, Boolean *bArg)
{
    GEDR0 |= XLLP_BIT_12;           // clear GPIO status
    if (FALSE == IsInPnPThd) {
        IsInPnPThd = TRUE;
        g_SdEvent.NotifyByIsr();
    }
}

ECode MiniSDPnPIst(void *arg)
{
    WaitResult wr;
    EmIsrParameter Param;
    ECode ec;
    while(1) {
        //SD_API_STATUS ret;
        g_SdEvent.Wait(&wr, NULL);
        //kputs("*****Processing ... ***** \n");
        Param.nParameter1 = Param.nParameter2 = 0;
        Param.nParameter3 = Param.nParameter4 = 0;
        if (GPLR0 & XLLP_BIT_12) {
            // Plug in
            kputs("MiniSD CARD INSERT\n");
            if ( SD_API_FAILED( g_SDBus.HandleAddDevice() ) ) {
                EmPostEventByIsr(112, &Param);//INSERT FAILED == REMOVE
                ec = E_DOES_NOT_EXIST;
            }
            else {
                EmPostEventByIsr(111, &Param);
                ec = NOERROR;
            }
        }
        else {
            kputs("MiniSD CARD EJECT\n");
            g_SDBus.HandleRemoveDevice();
            EmPostEventByIsr(112, &Param);
            ec = NOERROR;
        }
        //kputs("EmPost MiniSD Insert/Remove EventByIsr\n");
        IsInPnPThd = FALSE;
    }
    return ec;
}

ECode CreatePnPThread()
{
    ECode ec;
    ec = DzCreateKernelThread(MiniSDPnPIst,
         NULL, CreateThreadFlag_System, ThreadPriorityRank_Normal, NULL);

    if (FAILED(ec)) {
        DEBUGCHK(_DBGSD, kprintf("unable to create pnp thread ec : %08x\n", ec));
    }
    return ec;
}



EXTERN IDeviceDriver * CDECL CreateMiniSDBus(uint_t uDeviceNo, void *pvParameter)
{
    g_SDBus.Initialize();

    GRER0 |= (1 << 12);
    GFER0 |= (1 << 12);
    Drv_GpioInstall(12, (void*)&g_SDBus, (void *) MiniSDPnPIsr);
    if (FAILED(CreatePnPThread())) {
        goto __Exit;
    }
    DEBUGCHK(_DBGSD, kprintf("SD/MMC Bus Initialize!\n"));
    return (&g_SDBus);

__Exit:
    DEBUGCHK(_DBGSD, kprintf("SD/MMC Bus Initialize failed!\n"));
    return NULL;
}



